package com.simple.util.common;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

import com.simple.util.exception.AppException;
import com.simple.util.exception.ISimpleException;
import com.simple.util.exception.SimpleApplicationException;
import com.simple.util.exception.SimpleSystemException;
import com.simple.util.exception.SysException;
import com.simple.util.object.JFValidationBean;


public class ErrorUtil {
    /**
     * Generate jf validation from app exception.
     * 
     * @param apebException
     *            the apeb exception
     * @return the jF validation bean
     */
    public static JFValidationBean generateJFValidationFromAppException(
            final ISimpleException simpleException) {
        final JFValidationBean jfValidationBean = new JFValidationBean();
        if (null != simpleException) {
            jfValidationBean.setValidationId(simpleException.getCode());

            final List<String> paramList = new ArrayList<String>();
            final String[] array = simpleException.getParam();

            if (null != array) {
                paramList.addAll(Arrays.asList(array));
            }

            jfValidationBean.setParamList(paramList);
            
            if(simpleException.getParentThrowable()!=null){
                jfValidationBean.setThrowable((Throwable) simpleException);
            }
        }

        return jfValidationBean;
    }
    
    public static JFValidationBean generateJFValidationFromAppException(
                    final AppException appException) {
        final JFValidationBean jfValidationBean = new JFValidationBean();
        if (null != appException) {
            jfValidationBean.setValidationId(JFValidationBean.VALIDATION_ID_NO_ID+"-"+(new Date()).getTime());
            jfValidationBean.setValidationMsg(appException.getAppError());
            
            if(appException.getParentThrowable()!=null){
                jfValidationBean.setThrowable((Throwable) appException);
            }
        }
    
        return jfValidationBean;
    }
    
    public static JFValidationBean generateJFValidationFromSysException(
                    final SysException sysException) {
        final JFValidationBean jfValidationBean = new JFValidationBean();
        if (null != sysException) {
            jfValidationBean.setValidationId(JFValidationBean.VALIDATION_ID_NO_ID+"-"+(new Date()).getTime());
            jfValidationBean.setValidationMsg(sysException.getAppError());
            
            if(sysException.getParentThrowable()!=null){
                jfValidationBean.setThrowable((Throwable) sysException);
            }
        }
    
        return jfValidationBean;
    }
    
    /**
     * Generate stack trace string.
     * 
     * @param t
     *            the t
     * @return the string
     */
    public static String generateStackTraceString(final Throwable t) {
        final StringBuffer buffer = new StringBuffer(1000);
        if (null != t) {
            if (t instanceof SimpleApplicationException) {
                final SimpleApplicationException ae = (SimpleApplicationException) t;
                buffer.append("com.simple.util.exception.SimpleApplicationException : ");
                buffer.append(ae.getCode());
                buffer.append('\n');
                final Throwable throwable = ae.getParentThrowable();
                if (null != throwable) {
                    buffer.append("-------- nested by :\n");
                    buffer.append(generateStackTraceString(throwable));
                }
            } else {
                if (t instanceof SimpleSystemException) {
                    final SimpleSystemException ae = (SimpleSystemException) t;
                    buffer.append("com.simple.util.exception.SimpleSystemException : ");
                    buffer.append(ae.getCode());
                    buffer.append('\n');
                    final Throwable throwable = ae.getParentThrowable();
                    if (null != throwable) {
                        buffer.append("-------- nested by :\n");
                        buffer.append(generateStackTraceString(throwable));
                    }
                }else{
                    if(t instanceof AppException){
                        final AppException ae = (AppException) t;
                        buffer.append("com.simple.util.exception.AppException : ");
                        buffer.append(ae.getAppError());
                        buffer.append('\n');
                        final Throwable throwable = ae.getParentThrowable();
                        if (null != throwable) {
                            buffer.append("-------- nested by :\n");
                            buffer.append(generateStackTraceString(throwable));
                        }
                    }else{
                        if(t instanceof SysException){
                            final SysException ae = (SysException) t;
                            buffer.append("com.simple.util.exception.SysException : ");
                            buffer.append(ae.getAppError());
                            buffer.append('\n');
                            final Throwable throwable = ae.getParentThrowable();
                            if (null != throwable) {
                                buffer.append("-------- nested by :\n");
                                buffer.append(generateStackTraceString(throwable));
                            }
                        }else{
                            buffer.append(generateSystemStackTraceString(t));
                        }
                    }
                }
            }
        }
        return buffer.toString();
    }
    
    /**
     * Generate stack trace string.
     * 
     * @param t
     *            the t
     * @return the string
     */
    private static String generateSystemStackTraceString(final Throwable t) {
        String stackTrace = "";
        if (null != t) {
            final StringWriter sw = new StringWriter();
            t.printStackTrace(new PrintWriter(sw));
            stackTrace = sw.toString();
        }
        return stackTrace;
    }
    
    public static List<JFValidationBean> addExceptionToErrorList(final List<JFValidationBean> errorList,final Exception ex){
        return addExceptionToErrorList(errorList,ex,"message.system.error");
    }
    
    public static List<JFValidationBean> addExceptionToErrorList(final List<JFValidationBean> errorList,final Exception ex, final String defaultErrorCode){
        if (ex instanceof SimpleApplicationException || ex instanceof SimpleSystemException) {
            errorList.add(ErrorUtil.generateJFValidationFromAppException((ISimpleException) ex));
        } else {
            if(ex instanceof AppException){
                errorList.add(ErrorUtil.generateJFValidationFromAppException((AppException)ex));
            }
            else{
                if(ex instanceof SysException){
                    errorList.add(ErrorUtil.generateJFValidationFromSysException((SysException)ex));
                }else{
                    errorList.add(ErrorUtil.generateJFValidationFromAppException(new SimpleSystemException(defaultErrorCode,ex)));
                }
            }
        }
        return errorList;
    }
}
